package com.mlnx;

import com.mlnx.mptp.PacketType;
import com.mlnx.mptp.ResponseCode;
import com.mlnx.mptp.exception.InvalidPacketException;
import com.mlnx.mptp.model.ecg.ECGDeviceRunMode;
import com.mlnx.mptp.mptp.MpPacket;
import com.mlnx.mptp.mptp.VersionManager;
import com.mlnx.mptp.mptp.head.Header;
import com.mlnx.mptp.mptp.head.QoS;
import com.mlnx.tp.base.model.DeviceType;
import com.mlnx.tp.base.utils.ByteBuffUtils;
import com.mlnx.tp.base.utils.ByteUtils;
import com.mlnx.tp.base.utils.LogUtils;

import java.nio.ByteBuffer;
import java.util.Date;

import static com.mlnx.mptp.model.ecg.ECGChannelType.CHAN_8;

/**
 * Created by amanda.shan on 2019/5/17.
 */
public abstract class TestMpDecode2 {

    enum State {
        HEAD, VERSION, LEN, CONTANT
    }

    private State state = State.HEAD;
    private int matchHeadIndex;
    private int length;

//    public static void main(String[] args) throws Exception {
//        File file = new File("C:\\c.txt");
//        System.out.println(file.exists());
//
//        InputStream inputStream = new FileInputStream(file);
//
//        byte[] bytes = new byte[1000];
//        int len = 0;
//        MpPacket mpPacket;
//        ByteBuffer byteBuffer = ByteBuffer.allocate(10000000);
//        byteBuffer.flip();
//
//        TestMpDecode2 testMpDecode = new TestMpDecode2();
//
//        while ((len = inputStream.read(bytes)) > 0) {
//            LogUtils.i("len");
//            ByteBuffUtils.addBytes(byteBuffer, bytes, len);
//
//            testMpDecode.decode(byteBuffer);
//        }
//    }

    public abstract void sendRegAck(byte[] bytes);

    public abstract void sendPushAck(byte[] bytes);

    public void decode(ByteBuffer byteBuffer) throws Exception {

//        if (LogLevelInfo.getInstance().isOpenFrameLog())
//            LogUtils.mpFrame("recive  frame:" + ByteBufUtil.hexDump(in));

        switch (state) {
            case HEAD:
                if (matchHead(byteBuffer)) {
                    state = State.VERSION;
                } else {
                    break;
                }
            case VERSION:

                if (byteBuffer.hasRemaining()) {
                    byte code = byteBuffer.get();
                    if (VersionManager.isSupport(code)) {
                        state = State.LEN;
                    } else {
                        int mainCode = (code >> 4) & 0x0000000f;
                        int subCode = code & 0x0f;

                        LogUtils.e(String
                                .format("不支持的协议版本%d.%d", mainCode, subCode));
                        state = State.HEAD;
                        break;
                    }
                } else {
                    break;
                }
            case LEN:
                length = getPacketLength(byteBuffer);

                if (length > Header.MaxLength) {
                    LogUtils.w(String.format("数据包长度过长  实际包长度为%d", length));
                    state = State.HEAD;
                    break;
                } else if (length >= 0) {
                    state = State.CONTANT;
                    LogUtils.mpFrame("frame len:" + length);
                } else {
                    break;
                }
            case CONTANT:
                if (byteBuffer.remaining() >= length) {
                    byte[] bytes = new byte[length];
                    byteBuffer.get(bytes);
                    ByteBuffer bf = ByteBuffer.allocate(length);
                    bf.flip();
                    ByteBuffUtils.addBytes(bf, bytes);
                    try {

                        MpPacket mpPacket = new MpPacket();
                        mpPacket.decode(bf);

                        LogUtils.i(mpPacket.getHeader().getPacketType().toString());
                        if (PacketType.PUBLISH.equals(mpPacket.getHeader().getPacketType()) && QoS.LEAST_ONE.equals(mpPacket.getHeader().getQoS()))
                            sendPushAck(mpPacket.pushAck(DeviceType.SERVER, mpPacket.getBody().getMessageId(), ResponseCode.SUCESS).encode());
                        else if (PacketType.REGISTER.equals(mpPacket.getHeader().getPacketType()))
                            sendRegAck(mpPacket.registerAck(CHAN_8, ECGDeviceRunMode.STANDARD_MODE, DeviceType.SERVER, 18700, ResponseCode.SUCESS).encode());
                        else
                            LogUtils.i("包时间：" + new Date(mpPacket.getBody().getPacketTime()));
                    } catch (InvalidPacketException e) {
                        e.printStackTrace();
                    } finally {
                        state = State.HEAD;
                    }
                }
                break;
            default:
        }
    }

    private boolean matchHead(ByteBuffer buf) {

        while (buf.hasRemaining()) {
            if (matchHeadIndex == Header.Heads.length) {
                matchHeadIndex = 0;
                return true;
            }
            byte b = buf.get();
            if (b == Header.Heads[matchHeadIndex]) {
                matchHeadIndex++;
            } else if (b == Header.Heads[0]) {
                matchHeadIndex = 1;
            } else {
                matchHeadIndex = 0;
            }
        }
        return false;
    }

    private int getPacketLength(ByteBuffer buf) {
        if (buf.remaining() > Header.LengthByteSize) {
            byte[] dst = new byte[Header.LengthByteSize];
            buf.get(dst);
            int length = ByteUtils.bytesToInt(dst, Header.LengthByteSize);

            return length;
        } else {
            return -1;
        }
    }
}
